﻿using System.Globalization;
using System.Reflection;

namespace Basic.Repository.Abstract.SplitImpl;

public class BasicSplitTableService : ISplitTableService
{
    private IFormatProvider TimeFormatProvider = new CultureInfo("zh-CN", true);

    public List<SplitTableInfo> GetAllTables(ISqlSugarClient db, EntityInfo entityInfo, List<DbTableInfo> tableInfos)
    {
        List<SplitTableInfo> infos = new List<SplitTableInfo>();
        foreach (var table in tableInfos.Where(s => s.Name.StartsWith(entityInfo.DbTableName)))
        {
            string tbName = table.Name;
            string splitInfo = tbName.Replace($"{entityInfo.DbTableName}_", string.Empty);
            DateTime tbTime = DateTime.MinValue;

            if (!DateTime.TryParseExact(splitInfo, "yyyy", TimeFormatProvider, DateTimeStyles.None, out tbTime)
                && !DateTime.TryParseExact(splitInfo, "yyyy_MM", TimeFormatProvider, DateTimeStyles.None, out tbTime)
                && !DateTime.TryParseExact(splitInfo, "yyyy_MM_dd", TimeFormatProvider, DateTimeStyles.None, out tbTime))
            {
                if (splitInfo.Contains("_Season"))
                {
                    string[] strs = splitInfo.Split("_Season");
                    if (strs.Length > 1)
                    {
                        int season = int.Parse(strs[1]);
                        tbTime = new DateTime(int.Parse(strs[0]), 1, 1).AddMonths(season * 3);
                    }
                }
                if (splitInfo.Contains("_Week"))
                {
                    string[] strs = splitInfo.Split("_Week");
                    if (strs.Length > 1)
                    {
                        int week = int.Parse(strs[1]);
                        tbTime = new DateTime(int.Parse(strs[0]), 1, 1).AddDays(week * 7);
                    }
                }
                if (splitInfo.Contains("_Half"))
                {
                    string[] strs = splitInfo.Split("_Half");
                    if (strs.Length > 1)
                    {
                        int half = int.Parse(strs[1]);
                        tbTime = new DateTime(int.Parse(strs[0]), 1, 1).AddMonths(half * 6);
                    }
                }
            }
            infos.Add(new SplitTableInfo
            {
                TableName = table.Name,
                Date = tbTime,
            });
        }
        return infos.OrderByDescending(t => t.Date).ToList();
    }

    public object GetFieldValue(ISqlSugarClient db, EntityInfo entityInfo, SplitType splitType, object entityValue)
    {
        EntityColumnInfo splitColumn = entityInfo.Columns.FirstOrDefault(s => s.PropertyInfo.GetCustomAttribute<SplitFieldAttribute>() != null);
        if (splitColumn == null)
            return null;

        return splitColumn.PropertyInfo.GetValue(entityValue);
    }

    public string GetTableName(ISqlSugarClient db, EntityInfo entityInfo)
    {
        var attribute = entityInfo.Type.GetCustomAttribute<SplitTableAttribute>();
        if (attribute == null)
            return entityInfo.DbTableName;

        return GetTableName(db, entityInfo, attribute.SplitType, DateTime.Now);
    }

    public string GetTableName(ISqlSugarClient db, EntityInfo entityInfo, SplitType splitType)
    {
        return GetTableName(db, entityInfo, splitType, DateTime.Now);
    }

    public string GetTableName(ISqlSugarClient db, EntityInfo entityInfo, SplitType splitType, object fieldValue)
    {
        DateTime time;
        if (fieldValue is DateTime t1)
            time = t1.ToLocalTime();
        else if (fieldValue is DateTimeOffset t2)
            time = t2.ToLocalTime().DateTime;
        else
            throw new NotImplementedException("自定义分表字段仅支持DateTime/DateTimeOffset类型!");

        switch (splitType)
        {
            case SplitType.Year:
                return $"{entityInfo.DbTableName}_{time:yyyy}";
            case SplitType.Month:
                return $"{entityInfo.DbTableName}_{time:yyyy_MM}";
            case SplitType.Day:
                return $"{entityInfo.DbTableName}_{time:yyyy_MM_dd}";
            case SplitType.Week:
                {
                    DateTime start = new DateTime(time.Year, 1, 1);
                    var days = (int)((time.Date - start.Date).TotalDays);
                    return $"{entityInfo.DbTableName}_{time.Year}_Week{(days / 7)}";
                }
            case SplitType.Season:
                return $"{entityInfo.DbTableName}_{time.Year}_Season{((time.Month - 1) / 3)}";
            case SplitType.Month_6:
                return $"{entityInfo.DbTableName}_{time.Year}_Half{((time.Month - 1) / 6)}";
            default:
                return $"{entityInfo.DbTableName}_{time:yyyy}";
        }

    }

}